package com.vxfly.helioscamera.ExtendComponent;

import java.nio.ByteBuffer;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;

import com.vxfly.helioscamera.SDKAPI.VideoPlayback;
import com.vxfly.helioscamera.Tool.ScaleTool;
import com.vxfly.helioscamera.log.WriteLogToDevice;
import com.icatch.wificam.customer.ICatchWificamVideoPlayback;
import com.icatch.wificam.customer.exception.IchAudioStreamClosedException;
import com.icatch.wificam.customer.exception.IchBufferTooSmallException;
import com.icatch.wificam.customer.exception.IchCameraModeException;
import com.icatch.wificam.customer.exception.IchInvalidArgumentException;
import com.icatch.wificam.customer.exception.IchInvalidSessionException;
import com.icatch.wificam.customer.exception.IchPbStreamPausedException;
import com.icatch.wificam.customer.exception.IchSocketException;
import com.icatch.wificam.customer.exception.IchStreamNotRunningException;
import com.icatch.wificam.customer.exception.IchTryAgainException;
import com.icatch.wificam.customer.exception.IchVideoStreamClosedException;
import com.icatch.wificam.customer.type.ICatchAudioFormat;
import com.icatch.wificam.customer.type.ICatchFrameBuffer;

public class LocalVideoPbMjpg extends SurfaceView implements SurfaceHolder.Callback {

	private int frameWidth;
	private int frameHeight;
	private byte[] pixelBuf;
	private ByteBuffer bmpBuf;
	private Rect drawFrameRect;
	private Bitmap videoFrameBitmap;
	private VideoPlayback videoPlayback = VideoPlayback.getInstance();
	private ICatchWificamVideoPlayback videoPb;
	private int myWidth;
	private int myHeight;
	public final int ADJUST_LAYOUT_VIDEOPB = 1;

	private SurfaceHolder holder;
	private VideoThread mySurfaceViewThread;
	private boolean hasSurface = false;
	private AudioThread audioThread;
	private boolean hasInit = false;
	private AudioTrack audioTrack;
	private LocalMjpgVideoPbUpdateBarLitener videoPbUpdateBarLitener;
	private boolean videoThreadDone = false;

	public LocalVideoPbMjpg(Context context, AttributeSet attrs) {
		super(context, attrs);
		holder = this.getHolder();
		holder.addCallback(this);
		holder.setFormat(PixelFormat.RGBA_8888);
		this.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

			@Override
			public void onGlobalLayout() {
				// TODO Auto-generated method stub
				if (videoThreadDone) {
					reDrawBitmap();
					WriteLogToDevice.writeLog("[Normal] -- LocalVideoPbMjpg", "addOnGlobalLayoutListener");
				}
			}
		});
	}

	private void init() {
		frameWidth = 0;
		frameHeight = 0;
		// play之后还不能立马获取到frame 宽高，sdk获取到一帧才会获取到宽高;
		// 采用延时获取宽高，三次延时可以获取到;
		// JIRA ICOM-1912 Start:Add by b.jiang 2015-08-28
		while (frameWidth == 0 || frameHeight == 0) {
			frameWidth = videoPlayback.getVideoFormat().getVideoW();
			frameHeight = videoPlayback.getVideoFormat().getVideoH();
			WriteLogToDevice.writeLog("[Normal] -- LocalVideoPbMjpg: ", "init preview, VideoW =" + frameWidth);
			WriteLogToDevice.writeLog("[Normal] -- LocalVideoPbMjpg: ", "init preview, VideoH =" + frameHeight);
			try {
				Thread.sleep(33);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
		// JIRA ICOM-1912 End:Add by b.jiang 2015-08-28
		pixelBuf = new byte[frameWidth * frameHeight * 4];
		bmpBuf = ByteBuffer.wrap(pixelBuf);

		// Trigger onDraw with those initialize parameters
		videoFrameBitmap = Bitmap.createBitmap(frameWidth, frameHeight, Config.ARGB_8888);
		drawFrameRect = new Rect(0, 0, frameWidth, frameHeight);
		hasInit = true;
		myWidth = 0;
		myHeight = 0;
	}

	public void start(ICatchWificamVideoPlayback videoPlayBack) {

		Log.d("1111", "start preview   hasInit =" + hasInit);
		videoPb = videoPlayBack;
		videoPlayback.initVideoPlayback(videoPb);
		if (hasInit == false) {
			init();
		}
		// 创建和启动图像更新线程
		if (mySurfaceViewThread == null) {
			Log.d("1111", "mySurfaceViewThread == null) start new VideoThread!");
			mySurfaceViewThread = new VideoThread();
			WriteLogToDevice.writeLog("[Normal] -- LocalVideoPbMjpg: ", "hasSurface =" + hasSurface);
			if (hasSurface == true)
				mySurfaceViewThread.start();
		}
		// 启动音频线程
		if (audioThread == null) {
			audioThread = new AudioThread();
			audioThread.start();
		}
	}

	public boolean stop() {
		// 杀死图像更新线程
		Log.d("1111", "stop preview");
		if (mySurfaceViewThread != null) {
			mySurfaceViewThread.requestExitAndWait();
			mySurfaceViewThread = null;
		}

		// 杀死音频线程
		if (audioThread != null) {
			audioThread.requestExitAndWait();
			audioThread = null;
		}
		if (holder != null) {
			holder.removeCallback(this);
		}
		hasInit = false;
		Log.d("1111", "end preview");
		return true;
	}

	private class VideoThread extends Thread {
		VideoThread() {
			super();
			videoThreadDone = false;
		}

		@Override
		public void run() {
			WriteLogToDevice.writeLog("VideoPbMjpg", "start running VideoThread thread");
			SurfaceHolder surfaceHolder = holder;
			ICatchFrameBuffer buffer = new ICatchFrameBuffer(frameWidth * frameHeight * 4);
			buffer.setBuffer(pixelBuf);
			boolean temp = false;
			while (!videoThreadDone) {
				// ICOM-1913 ICOM-1911 End add by b.jiang 2015-08-28
				// 当宽高改变时，重新绘制画面;
				if (myWidth != getWidth() || myHeight != getHeight()) {
					if (getWidth() > 0 || getHeight() > 0) {
						myWidth = getWidth();
						myHeight = getHeight();
						WriteLogToDevice.writeLog("[Normal] -- LocalVideoPbMjpg: ", "videoFrameBitmap=" + videoFrameBitmap);
						WriteLogToDevice.writeLog("[Normal] -- LocalVideoPbMjpg: ", "Width=" + getWidth() + " Height" + getHeight());
						if (videoFrameBitmap != null) {
							Canvas canvas = surfaceHolder.lockCanvas();
							drawFrameRect = ScaleTool.getScaledPosition(frameWidth, frameHeight, getWidth(), getHeight());
							canvas.drawBitmap(videoFrameBitmap, null, drawFrameRect, null);
							surfaceHolder.unlockCanvasAndPost(canvas);
						}
					}
				}
				// ICOM-1913 ICOM-1911 End add by b.jiang 2015-08-28

				temp = false;
				try {
					// WriteLogToDevice.writeLog("[Error] -- Preview: ",
					// "start getNextVideoFrame");
					temp = videoPb.getNextVideoFrame(buffer);
				} catch (IchSocketException e) {
					WriteLogToDevice.writeLog("[Error] -- LocalVideoPbMjpg: ", "IchSocketException");
					// need to close preview get next video frame
					// TODO Auto-generated catch block
					e.printStackTrace();
					return;
				} catch (IchBufferTooSmallException e) {
					WriteLogToDevice.writeLog("[Error] -- LocalVideoPbMjpg: ", "IchBufferTooSmallException");
					// TODO Auto-generated catch block
					e.printStackTrace();
					return;
				} catch (IchCameraModeException e) {
					WriteLogToDevice.writeLog("[Error] -- LocalVideoPbMjpg: ", "IchCameraModeException");
					// TODO Auto-generated catch block
					e.printStackTrace();
					return;
				} catch (IchInvalidSessionException e) {
					WriteLogToDevice.writeLog("[Error] -- LocalVideoPbMjpg: ", "IchInvalidSessionException");
					// TODO Auto-generated catch block
					e.printStackTrace();
					return;
				} catch (IchTryAgainException e) {
					// WriteLogToDevice.writeLog("[Error] -- LocalVideoPbMjpg: ",
					// "IchTryAgainException");
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IchStreamNotRunningException e) {
					WriteLogToDevice.writeLog("[Error] -- LocalVideoPbMjpg: ", "IchStreamNotRunningException");
					// TODO Auto-generated catch block
					e.printStackTrace();
					return;
				} catch (IchInvalidArgumentException e) {
					WriteLogToDevice.writeLog("[Error] -- LocalVideoPbMjpg: ", "IchInvalidArgumentException");
					// TODO Auto-generated catch block
					e.printStackTrace();
					return;
				} catch (IchVideoStreamClosedException e) {
					WriteLogToDevice.writeLog("[Error] -- LocalVideoPbMjpg: ", "IchVideoStreamClosedException");
					// TODO Auto-generated catch block
					e.printStackTrace();
					return;
				} catch (IchPbStreamPausedException e) {
					// TODO Auto-generated catch block
					WriteLogToDevice.writeLog("[Error] -- LocalVideoPbMjpg: ", "IchPbStreamPausedException");
					e.printStackTrace();
				}
				// WriteLogToDevice.writeLog("[Normal] -- PreviewStream: ",
				// "end getNextVideoFrame retValue =" + retValue);
				if (temp == false) {
					continue;
				}
				if (buffer == null) {
					WriteLogToDevice.writeLog("[Error] -- LocalVideoPbMjpg: ", "buffer == null\n");
					Log.e("Preview", "break");
					continue;
				}
				bmpBuf.rewind();
				videoFrameBitmap.copyPixelsFromBuffer(bmpBuf);
				// 锁定surface，并返回到要绘图的Canvas
				Canvas canvas = surfaceHolder.lockCanvas();
				drawFrameRect = ScaleTool.getScaledPosition(frameWidth, frameHeight, getWidth(), getHeight());
				canvas.drawBitmap(videoFrameBitmap, null, drawFrameRect, null);
				// // 解锁Canvas，并渲染当前图像
				surfaceHolder.unlockCanvasAndPost(canvas);

				// JIRA ICOM-1889 Start change by b.jiang 20150821
				videoPbUpdateBarLitener.updateBar(buffer.getPresentationTime());
				// JIRA ICOM-1889 End change by b.jiang 20150821

				// handler.obtainMessage(GlobalInfo.MESSAGE_UPDATE_VIDEOPB_BAR,(int)
				// buffer.getPresentationTime(),0).sendToTarget();
			}
			Log.d("1111", "stop video thread");
		}

		public void requestExitAndWait() {
			// 把这个线程标记为完成，并合并到主程序线程
			videoThreadDone = true;
			try {
				join();
			} catch (InterruptedException ex) {
			}
		}

	}

	private class AudioThread extends Thread {
		private boolean done = false;

		public void run() {
			WriteLogToDevice.writeLog("[Normal] -- PbVideoActivity", "start AudioThread.....");
			if (videoPlayback.containsAudioStream() == false) {
				return;
			}
			ICatchAudioFormat audioFormat = videoPlayback.getAudioFormat();
			int bufferSize = AudioTrack.getMinBufferSize(audioFormat.getFrequency(), audioFormat.getNChannels() == 2 ? AudioFormat.CHANNEL_IN_STEREO
					: AudioFormat.CHANNEL_IN_LEFT, audioFormat.getSampleBits() == 16 ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT);

			audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, audioFormat.getFrequency(), audioFormat.getNChannels() == 2 ? AudioFormat.CHANNEL_IN_STEREO
					: AudioFormat.CHANNEL_IN_LEFT, audioFormat.getSampleBits() == 16 ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT,
					bufferSize, AudioTrack.MODE_STREAM);
			WriteLogToDevice.writeLog("1111", "start AudioTrack play");
			audioTrack.play();
			Log.d("1111", "audioTrack play");
			byte[] audioBuffer = new byte[1024 * 50];
			ICatchFrameBuffer icatchBuffer = new ICatchFrameBuffer();
			icatchBuffer.setBuffer(audioBuffer);
			boolean temp = false;
			WriteLogToDevice.writeLog("[Normal] -- getNextAudioFrame", "start getNextAudioFrame");
			while (!done) {
				temp = false;
				try {
					temp = videoPb.getNextAudioFrame(icatchBuffer);
				} catch (IchSocketException e) {
					WriteLogToDevice.writeLog("[Error] -- AudioThread: ", "videoPb.getNextAudioFrame IchSocketException");
					// TODO Auto-generated catch block
					e.printStackTrace();
					return;
				} catch (IchCameraModeException e) {
					WriteLogToDevice.writeLog("[Error] -- AudioThread: ", "videoPb.getNextAudioFrame IchCameraModeException");
					// TODO Auto-generated catch block
					e.printStackTrace();
					return;
				} catch (IchInvalidSessionException e) {
					WriteLogToDevice.writeLog("[Error] -- AudioThread: ", "videoPb.getNextAudioFrame IchInvalidSessionException");
					// TODO Auto-generated catch block
					e.printStackTrace();
					return;
				} catch (IchStreamNotRunningException e) {
					WriteLogToDevice.writeLog("[Error] -- AudioThread: ", "videoPb.getNextAudioFrame IchStreamNotRunningException");
					// TODO Auto-generated catch block
					e.printStackTrace();
					return;
				} catch (IchBufferTooSmallException e) {
					// TODO Auto-generated catch block
					WriteLogToDevice.writeLog("[Error] -- AudioThread: ", "videoPb.getNextAudioFrame IchBufferTooSmallException");
					e.printStackTrace();
					return;
				} catch (IchTryAgainException e) {
					// TODO Auto-generated catch block
					// WriteLogToDevice.writeLog("[Error] -- AudioThread: ",
					// "videoPb.getNextAudioFrame IchTryAgainException");
					e.printStackTrace();
					continue;
				} catch (IchInvalidArgumentException e) {
					// TODO Auto-generated catch block
					WriteLogToDevice.writeLog("[Error] -- AudioThread: ", "videoPb.getNextAudioFrame IchInvalidArgumentException");
					e.printStackTrace();
					return;
				} catch (IchAudioStreamClosedException e) {
					// TODO Auto-generated catch block
					// WriteLogToDevice.writeLog("[Error] -- AudioThread: ",
					// "videoPb.getNextAudioFrame IchAudioStreamClosedException");
					e.printStackTrace();
				} catch (IchPbStreamPausedException e) {
					// TODO Auto-generated catch block
					// WriteLogToDevice.writeLog("[Error] -- AudioThread: ",
					// "videoPb.getNextAudioFrame IchPbStreamPausedException");
					e.printStackTrace();
				}
				if (false == temp) {
					// WriteLogToDevice.writeLog("[Error] -- AudioThread: ",
					// "failed to getNextAudioFrame");
					continue;
				} else {
					// WriteLogToDevice.writeLog("[Normal] -- AudioThread: ",
					// "success to getNextAudioFrame");
				}
				if (icatchBuffer == null) {
					WriteLogToDevice.writeLog("[Normal] -- AudioThread", "buffer == null");
					continue;
				}
				audioTrack.write(icatchBuffer.getBuffer(), 0, icatchBuffer.getFrameSize());
			}
			audioTrack.stop();
			audioTrack.release();
			WriteLogToDevice.writeLog("[Normal] -- PreviewMjpg: ", "stop audio thread");
		}

		public void requestExitAndWait() {
			// 把这个线程标记为完成，并合并到主程序线程
			done = true;
			try {
				join();
			} catch (InterruptedException ex) {
			}
		}
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		Log.d("1111", "surfaceCreated");
		WriteLogToDevice.writeLog("test", "surfaceCreated");
		hasSurface = true;
		if (mySurfaceViewThread != null) {
			Log.d("1111", "surfaceCreated start mySurfaceViewThread");
			if (mySurfaceViewThread.isAlive() == false) {
				Log.d("1111", "surfaceCreated mySurfaceViewThread.isAlive() == false");
				mySurfaceViewThread.start();
			}
		}
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		WriteLogToDevice.writeLog("test", "surfaceDestroyed");
		Log.d("tigertiger", "surfaceDestroyed");
		Log.d("1111", " surfaceDestroyed");
		hasSurface = false;
		stop();
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
		Log.d("1111", " surfaceChanged");
		WriteLogToDevice.writeLog("test ", "surfaceChanged");
		SurfaceHolder surfaceHolder = holder;
		if (videoFrameBitmap != null) {
			Canvas canvas = surfaceHolder.lockCanvas();
			drawFrameRect = ScaleTool.getScaledPosition(frameWidth, frameHeight, getWidth(), getHeight());
			canvas.drawBitmap(videoFrameBitmap, null, drawFrameRect, null);
			surfaceHolder.unlockCanvasAndPost(canvas);
		}
	}

	public void destorySurface() {
		hasSurface = false;
	}

	public interface LocalMjpgVideoPbUpdateBarLitener {
		void updateBar(double pts);
	}

	public void addVideoPbUpdateBarLitener(LocalMjpgVideoPbUpdateBarLitener videoPbUpdateBarLitener) {
		// h264ImageLitener.isShown();
		this.videoPbUpdateBarLitener = videoPbUpdateBarLitener;
	}

	public void reDrawBitmap() {
		SurfaceHolder surfaceHolder = holder;
		WriteLogToDevice.writeLog("test ", "reDrawBitmap videoFrameBitmap=" + videoFrameBitmap);
		WriteLogToDevice.writeLog("test ", "reDrawBitmap Width=" + getWidth() + " Height=" + getHeight());
		if (videoFrameBitmap != null) {
			Canvas canvas = surfaceHolder.lockCanvas();
			drawFrameRect = ScaleTool.getScaledPosition(frameWidth, frameHeight, getWidth(), getHeight());
			canvas.drawBitmap(videoFrameBitmap, null, drawFrameRect, null);
			surfaceHolder.unlockCanvasAndPost(canvas);
		}
	}
}
